﻿///////////////////////////////////////////////////////////////////////////////
//
//  This source is part of the  "Managed Task Framework.NET Runtime"  (MTF.NET Runtime).
//
//
//  Copyright (c) 2011, Multicore Consulting Limited (UK)
//  All rights reserved.
//  http://www.multicoreconsulting.co.uk
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//  -  Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  -  Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in
//     the documentation and/or other materials provided with the
//     distribution.
//  -  Neither the name of Multicore Consulting Limited nor the names of
//     its contributors may be used to endorse or promote products
//     derived from this software without specific prior written
//     permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using MTFOrg.MTF.MTFRuntime;
using MTFOrg.MTF.MTFCore;

namespace MTFOrg.MTF.MTFBlocks
{
    /// <summary>
    /// Task class for a generic output device.
    /// </summary>
    public partial class OutputDevice
    {
        /// <summary>
        /// Input queue interface
        /// </summary>
        public interface IInputQueue
        {
            /// <summary>
            /// Read from the output queue.
            /// </summary>
            /// <param name="elementNumber">Element number of queue to read from</param>
            /// <returns>Object received from input</returns>
            EventDictionary Read(int elementNumber);
        }

        /// <summary>
        /// Output thread handler interface
        /// </summary>
        public interface IOutputThreadHandler
        {
            /// <summary>
            /// Called to initialize data prior to execution.
            /// </summary>
            void OnInitialize(IInputQueue inputQueue);

            /// <summary>
            /// Called to run the thread.
            /// </summary>
            /// <param name="inputQueue">Interface to access the input queue</param>
            void ThreadFunction(IInputQueue inputQueue);
        }

        /// <summary>
        /// Input queue.
        /// </summary>
        protected class InputQueue : IInputQueue
        {
            /// <summary>
            /// Interface to request events from the output queue.
            /// </summary>
            IRequestable m_QueueRequester;

            /// <summary>
            /// Constructor.
            /// </summary>
            /// <param name="queueRequester">Queue requester</param>
            public InputQueue(IRequestable queueRequester)
            {
                m_QueueRequester = queueRequester;
            }

            /// <summary>
            /// Reads from the output queue using a non-default read tag.
            /// </summary>
            /// <param name="elementNumber">Element number of queue to read from</param>
            /// <returns>Object received from input</returns>
            public EventDictionary Read(int elementNumber)
            {
                EventDictionary reqEvent = m_QueueRequester.Request(elementNumber) as EventDictionary;
                m_QueueRequester.Release(elementNumber);
                return reqEvent;
            }
        }

        /// <summary>
        /// Output thread.
        /// </summary>
        protected Thread m_OutputThread;

        /// <summary>
        /// Output thread handler.
        /// </summary>
        protected IOutputThreadHandler m_ThreadHandler;

        /// <summary>
        /// Input queue.
        /// </summary>
        protected IInputQueue m_InputQueue;

        /// <summary>
        /// Called to initialize this task.
        /// </summary>
        public override void OnInitialize()
        {
            base.OnInitialize();

            // Create the input queue, thread handler and output thread
            m_InputQueue = new InputQueue(m_OutputDeviceInputTask);
            if (HandlerClass != null)
                m_ThreadHandler = Activator.CreateInstance(HandlerClass) as IOutputThreadHandler;
            m_OutputThread = new Thread(OutputThreadFunction);

            // Give the input thread opportunity to initialize
            if (HandlerClass != null)
                m_ThreadHandler.OnInitialize(m_InputQueue);
        }

        /// <summary>
        /// Called to start execution.
        /// </summary>
        public override void OnBeginExecution()
        {
            // Start the input thread.
            if (EnableThread && HandlerClass != null)
                m_OutputThread.Start();

            base.OnBeginExecution();
        }

        /// <summary>
        /// Thread function called to execute input thread code.
        /// </summary>
        protected void OutputThreadFunction()
        {
            // Call into the user-defined thread handler
            m_ThreadHandler.ThreadFunction(m_InputQueue);
        }
    }
}